package com.cskaoyan.javase.oop2._1extends._8hidden;

/**
 * 继承中父子类成员变量的隐藏
 *
 * 继承中,父子类中允许出现同名的成员变量,那么:
 *      在不使用super进行区分的前提下,来创建子类对象
 *      用子类对象名点访问该同名成员变量,那么它的取值是什么呢?
 *      它的取值显然是子类中成员变量的取值.
 *      这时,父类中的同名a去哪里了呢?
 *      首先a是存在的,可以用父类的Getter方法或者super去访问父类同名的a,那么之所以访问不到父类的成员变量a,是因为访问机制的限制.
 *      这种访问的机制称之为"属性的隐藏"
 *
 * 接下来重点研究"对象名点成员变量"的访问机制,主要是以下两点:
 *      1.访问范围,即能够访问什么
 *      2.访问结果,即访问到的是什么值
 *
 * 在本案例三个类中,创建对象,用对象名点访问成员变量有三种方式:
 *      1.创建父类Father对象,用父类引用Father接收
 *      2.创建子类Son对象,用子类引用Son接收
 *      3.创建子类Son对象,用父类引用Father接收
 *
 * 首先研究访问范围:
 *      1.创建父类Father对象,用父类引用Father接收
 *          只能直接访问父类中存在的成员变量
 *
 *      2.创建子类Son对象,用子类引用Son接收
 *          能够访问自身的成员,同时也能访问父类中继承过来的成员.
 *          也就是说访问范围是子类+父类
 *
 *      3.创建子类Son对象,用父类引用Father接收
 *          只能直接访问父类中存在的成员变量\
 *
 *  综上所述,得出结论:
 *      "对象名点"访问成员变量,它的访问范围是根据引用来决定的:
 *        1.引用的数据类型如果是父类的类型,那只能访问父类自身的成员变量.
 *        2.引用的数据类型如果是子类的类型,那就能访问子类+父类的成员变量
 *
 *        "对象名点"访问成员变量,它的访问范围是一个编译时就会检查的,它是一个编译时的概念.之所以根据引用的类型来决定,这是因为"变量的声明"的语法中,数据类型那个语法就是告诉编译器这个变量的数据类型,编译器就会根据这个数据类型然后去查找,查找的机制是:
 *          1.先去声明的引用的数据类型的那个类中去找
 *              找到了就不会报错
 *          2.找不到就去父类中找,直到找到Object类中
 *          3.还找不到就会编译报错.
 *
 * 思考:
 *      编译器知不知道一个类有父类?
 *      知道,因为直接声明
 *      但是一个类知不知道自己有子类呢?
 *      不知道
 *      所以编译器查找访问范围时只能向上找
 *      不会向下找
 *
 *
 * 接下来研究访问结果:
 *      1.创建父类Father对象,用父类引用Father接收
 *      2.创建子类Son对象,用子类引用Son接收
 *      3.创建子类Son对象,用父类引用Father接收
 *
 *  通过测试,对象名点访问成员变量的结果,只和引用的类型有关.引用的类中成员变量的取值就是访问的结果.
 *
 *
 *  综上所述,在使用对象名点访问成员变量时,
 *  访问范围看引用
 *  访问结果还看引用
 *  和对象的类型没有关系
 *
 *
 * @since 15:29
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Son s = new Son();
        System.out.println(s.a);*/

        /*Son s = new Son(100, 200);
        System.out.println(s.a);*/

       /* // 三种方式创建对象*/
       /* Father f = new Father();*/
       /* Son s = new Son();*/
       /* Father fs = new Son();*/
       /* System.out.println(fs.a);*/
       /* System.out.println(fs.fatherVar);*/
       /* // fs引用如果不强转成子类引用,无法直接访问子类独有成员*/
       /* // ((Son) fs).sonVar*/
       /* // Cannot resolve symbol 'sonVar'*/
       /* // System.out.println(fs.sonVar);*/


        Father f = new Father();
        System.out.println(f.a);
        Son s = new Son();
        System.out.println(s.a);
        Father fs = new Son();
        System.out.println(fs.a);

    }
}

class Father {
    int a = 10;
    int fatherVar = 20;
}

class Son extends Father {
    int a = 100;
    int sonVar = 200;
}